package com.promise.paging

import android.arch.lifecycle.MutableLiveData
import android.arch.paging.PageKeyedDataSource
import retrofit2.Call
import retrofit2.Response
import java.io.IOException
import java.util.concurrent.Executor

/**
 * Created by CQNNJ-003 on 2018/6/8.
 */
class PageKeyedUserDataSource(private val redditApi: Api, private val retryExecutor: Executor) : PageKeyedDataSource<String, QuestsData>() {

    private var retry: (() -> Any)? = null

    fun retryAllFailed() {
        val prevRetry = retry
        retry = null
        prevRetry?.let {
            retryExecutor.execute {
                it.invoke()
            }
        }
    }

    val initialLoad = MutableLiveData<NetworkState>()

    override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<String, QuestsData>) {

    }

    override fun loadInitial(params: LoadInitialParams<String>, callback: LoadInitialCallback<String, QuestsData>) {
        val request = redditApi.getTopAfter( limit = params.requestedLoadSize)


        initialLoad.postValue(NetworkState.LOADING)

        // triggered by a refresh, we better execute sync
        try {
            val response = request.execute()
            val data = response.body()?.data
            val items = data?.children?.map { it.data } ?: emptyList()
            retry = null
            initialLoad.postValue(NetworkState.LOADED)
            callback.onResult(items, data?.before, data?.after)
        } catch (ioException: IOException) {
            retry = { loadInitial(params, callback) }
            val error = NetworkState.error(ioException.message ?: "unknown error")
            initialLoad.postValue(error)
        }
    }

    override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<String, QuestsData>) {
        redditApi.getTopAfter(
                limit = params.requestedLoadSize).enqueue(
                object : retrofit2.Callback<Api.ListingResponse> {
                    override fun onFailure(call: Call<Api.ListingResponse>?, t: Throwable) {
                        retry = {
                            loadAfter(params, callback)
                        }
                    }

                    override fun onResponse(call: Call<Api.ListingResponse>, response: Response<Api.ListingResponse>) {
                        if (response.isSuccessful) {
                            val data = response.body()?.data
                            val items = data?.children?.map { it.data } ?: emptyList()
                            retry = null
                            callback.onResult(items, data?.after)
                        } else {
                            retry = {
                                loadAfter(params, callback)
                            }
                        }
                    }
                }
        )

    }
}